/*	--- 其他操作 --- 


我们把【Stream提供的操作】分为2类： 【转换操作】 和 【聚合操作】。

除了前面介绍的常用操作外, 【Stream】还提供了一系列非常有用的方法。

=======================


#	排序

对【Stream的元素】进行排序十分简单, 只需调用【sorted()方法】：*/
import java.util.*；
import java.util.stream.*;

public class Main {
	public static void main(String[] args) {
		List<String> list = List.of("Orange", "apple", "Banana")
			.stream()
			.sorted()
			.collect(Collectors.toList());

		System.out.println(list);
	}
}


/*
此方法要求【Stream的每个元素】必须实现【Comparable接口】。

如果要【自定义排序】, 传入【指定的Comparator】即可：*/
List<String> list = List.of("Orange", "apple", "Banana")
	.stream()
	.sorted(String::compareToIgnoreCase)
	.collect(Collectors.toList());

/*
注意 sorted() 只是一个【转换操作】, 它会返回【一个新的Stream】。


===================================================


#	去重

对一个Stream的元素进行去重, 没必要先转换为Set, 可以直接用distinct()：*/
List.of("A", "B", "A", "C", "B", "D")
	.stream()
	.distinct()
	.collect(Collectors.toList()); // [A, B, C, D]


/*==========================================================


#	截取

截取操作常用于把【一个无限的Stream】 转换成 【有限的Stream】, 

skip() 用于 跳过 当前Stream的前N个元素,  

limit()用于 截取 当前Stream最多前N个元素：*/
List.of("A", "B", "C", "D", "E", "F")
	.stream()
	.skip(2) // 跳过A, B
	.limit(3) // 截取C, D, E
	.collect(Collectors.toList());

/*
截取操作也是一个转换操作, 将返回新的Stream。


=========================================


#	合并

将【两个Stream】合并为【一个Stream】可以使用【Stream的静态方法concat()】：*/
Stream<String> s1 = List.of("A", "B", "C")
						.stream();

Stream<String> s2 = List.of("D", "E")
						.stream();

// 合并
Stream<String> s = Stream.concat(s1, s2);
System.out.println(s.collect(Collectors.toList()));
	// [A, B, C, D, E]


/*=======================================================


#	flatMap

如果【Stream的元素】是【集合】：*/
Stream<List<Integer>> s = Stream.of(
	Arrays.asList(1, 2, 3),
	Arrays.asList(4, 5, 6),
	Arrays.asList(7, 8, 9)
);

/*
而我们希望把 上述Stream 转换为 Stream<Integer>, 

就可以使用 flatMap()：*/
Stream<Integer> i = s.flatMap(list -> list.stream());


/*
因此, 所谓 flatMap(), 是指把【Stream的每个元素】（这里是List）映射为【Stream】, 

然后【合并成一个新的Stream】：

	┌─────────────┬─────────────┬─────────────┐
	│┌───┬───┬───┐│┌───┬───┬───┐│┌───┬───┬───┐│
	││ 1 │ 2 │ 3 │││ 4 │ 5 │ 6 │││ 7 │ 8 │ 9 ││
	│└───┴───┴───┘│└───┴───┴───┘│└───┴───┴───┘│
	└─────────────┴─────────────┴─────────────┘
	                     │
	                     │flatMap(List -> Stream)
	                     │
	                     │
	                     ▼
	   ┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
	   │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │
	   └───┴───┴───┴───┴───┴───┴───┴───┴───┘


======================================================


#	并行

通常情况下, 对【Stream的元素】进行【处理】是【单线程】的, 即一个一个元素进行处理。

但是很多时候, 我们希望可以【并行处理Stream的元素】, 因为在【元素数量非常大】的情况, 【并行处理】可以大大加快处理速度。

把【一个普通Stream】转换为【可以并行处理的Stream】非常简单, 只需要用 parallel() 进行转换：*/
Stream<String> s = List.of("A", "B", "C")
						.stream();

String[] result = s.parallel() // 变成一个可以并行处理的Stream
					.sorted() // 可以进行并行排序
					.toArray(String[]::new);


/*
经过 parallel() 转换后的 Stream 只要可能, 就会对后续操作进行【并行处理】。

我们不需要编写【任何多线程代码】就可以享受到【并行处理】带来的执行效率的提升。


=====================================================


#	其他聚合方法

除了reduce()和collect()外, Stream还有一些【常用的聚合方法】：

	· count()：用于返回元素个数；
	· max(Comparator<? super T> cp)：找出最大元素；
	· min(Comparator<? super T> cp)：找出最小元素。
	

针对IntStream、LongStream和DoubleStream, 还额外提供了以下【聚合方法】：
	· sum()：对所有元素求和；
	· average()：对所有元素求平均数。


还有一些方法, 用来【测试】 Stream的元素 是否满足 以下条件：
	· boolean allMatch(Predicate<? super T>)：
		测试是否所有元素均满足测试条件；
	· boolean anyMatch(Predicate<? super T>)：
		测试是否至少有一个元素满足测试条件。


最后一个常用的方法是 forEach() , 它可以循环处理Stream的每个元素, 

我们经常传入 System.out::println 来打印Stream的元素：*/
Stream<String> s = ...;

s.forEach(str -> {
    System.out.println("Hello, " + str);
});



/*========================================================


#	----- 其他操作 の 小结 -----


Stream提供的常用操作有：

	【转换操作】：map(), filter(), sorted(), distinct()；

	【合并操作】：concat(), flatMap()；

	【并行处理】：parallel()；

	【聚合操作】：reduce(), collect(), count(), max(), min(), sum(), average()；

	【其他操作】：allMatch(), anyMatch(), forEach()。






*/





